//
// This code was created by Jeff Molofee '99 (ported to Linux/GLUT by Richard Campbell '99)
//
// If you've found this code useful, please let me know.
//
// Visit me at www.demonews.com/hosted/nehe
// (email Richard Campbell at ulmont@bellsouth.net)
//
#include <GL/glut.h>    // Header File For The GLUT Library
#include <GL/gl.h>	// Header File For The OpenGL32 Library
#include <GL/glu.h>	// Header File For The GLu32 Library
#include <unistd.h>     // Header file for sleeping.

#include <cstdio>

/* ascii code for the escape key */
#define ESCAPE 27

using namespace std;

/* The number of our GLUT window */
int window;
bool keys[256];
bool fullscreen = true;

GLfloat     rtri = 0.0;                     // Angle For The Triangle
GLfloat     rquad = 0.0;                    // Angle For The Quad

/* A general OpenGL initialization function.  Sets all of the initial parameters. */
void InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
	glShadeModel(GL_SMOOTH);				// Enables Smooth Color Shading
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);	// This Will Clear The Background Color To Black
	glClearDepth(1.0);						// Enables Clearing Of The Depth Buffer
	glDepthFunc(GL_LESS);					// The Type Of Depth Test To Do
	glEnable(GL_DEPTH_TEST);				// Enables Depth Testing

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();						// Reset The Projection Matrix

	gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);	// Calculate The Aspect Ratio Of The Window

	glMatrixMode(GL_MODELVIEW);
}

/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
	if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
		Height=1;

	glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
	glMatrixMode(GL_MODELVIEW);

	glLoadIdentity();
}

/* The main drawing function. */
void DrawGLScene()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     // Clear The Screen And The Depth Buffer
	glLoadIdentity();                       				// Reset The View

	glTranslatef(-1.5f,0.0f,-6.0f);                 // Move Left 1.5 Units And Into The Screen 6.0

	glRotatef(rtri,1.0f,0.0f,0.0f);             	// Rotate The Triangle On The Y axis

	glBegin(GL_TRIANGLES);			// Drawing a Pyramid
		glColor3f(1.0f,0.0f,0.0f);          // Red
		glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Front)
		glColor3f(0.0f,1.0f,0.0f);          // Green
		glVertex3f(-1.0f,-1.0f, 1.0f);          // Left Of Triangle (Front)
		glColor3f(0.0f,0.0f,1.0f);          // Blue
		glVertex3f( 1.0f,-1.0f, 1.0f);          // Right Of Triangle (Front)
		glColor3f(1.0f,0.0f,0.0f);          // Red
		glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Right)
		glColor3f(0.0f,0.0f,1.0f);          // Blue
		glVertex3f( 1.0f,-1.0f, 1.0f);          // Left Of Triangle (Right)
		glColor3f(0.0f,1.0f,0.0f);          // Green
		glVertex3f( 1.0f,-1.0f, -1.0f);         // Right Of Triangle (Right)
		glColor3f(1.0f,0.0f,0.0f);          // Red
		glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Back)
		glColor3f(0.0f,1.0f,0.0f);          // Green
		glVertex3f( 1.0f,-1.0f, -1.0f);         // Left Of Triangle (Back)
		glColor3f(0.0f,0.0f,1.0f);          // Blue
		glVertex3f(-1.0f,-1.0f, -1.0f);         // Right Of Triangle (Back)
		glColor3f(1.0f,0.0f,0.0f);          // Red
		glVertex3f( 0.0f, 1.0f, 0.0f);          // Top Of Triangle (Left)
		glColor3f(0.0f,0.0f,1.0f);          // Blue
		glVertex3f(-1.0f,-1.0f,-1.0f);          // Left Of Triangle (Left)
		glColor3f(0.0f,1.0f,0.0f);          // Green
		glVertex3f(-1.0f,-1.0f, 1.0f);          // Right Of Triangle (Left)
	glEnd();                        // Done Drawing The Pyramid

	glBegin(GL_QUADS);				// Drawing the base of the Pyramid
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f(-1.0f,-1.0f,1.0f);			// Left Front
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f(1.0f,-1.0f,1.0f);			// Right Front
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f(1.0f,-1.0f,-1.0f);			// Right Back
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f(-1.0f,-1.0f,-1.0f);			// Left Back
	glEnd();						// Done drawing the Pyramid

	glLoadIdentity();

	glTranslatef(1.5f,0.0f,-6.0f);                  // Move Right 3 Units
	glRotatef(rquad,1.0f,1.0f,0.0f);

	glColor3f(0.5f,1.0f,0.5f);              		// Set The Color To Blue One Time Only
	glBegin(GL_QUADS);                      		// Draw A Quad
		glColor3f(0.0f,1.0f,0.0f);          // Set The Color To Green
		glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Top)
		glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Top)
		glVertex3f(-1.0f, 1.0f, 1.0f);          // Bottom Left Of The Quad (Top)
		glVertex3f( 1.0f, 1.0f, 1.0f);          // Bottom Right Of The Quad (Top)
		glColor3f(1.0f,0.5f,0.0f);          // Set The Color To Orange
		glVertex3f( 1.0f,-1.0f, 1.0f);          // Top Right Of The Quad (Bottom)
		glVertex3f(-1.0f,-1.0f, 1.0f);          // Top Left Of The Quad (Bottom)
		glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Bottom)
		glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Bottom)
		glColor3f(1.0f,0.0f,0.0f);          // Set The Color To Red
		glVertex3f( 1.0f, 1.0f, 1.0f);          // Top Right Of The Quad (Front)
		glVertex3f(-1.0f, 1.0f, 1.0f);          // Top Left Of The Quad (Front)
		glVertex3f(-1.0f,-1.0f, 1.0f);          // Bottom Left Of The Quad (Front)
		glVertex3f( 1.0f,-1.0f, 1.0f);          // Bottom Right Of The Quad (Front)
		glColor3f(1.0f,1.0f,0.0f);          // Set The Color To Yellow
		glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Back)
		glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Back)
		glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Back)
		glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Back)
		glColor3f(0.0f,0.0f,1.0f);          // Set The Color To Blue
		glVertex3f(-1.0f, 1.0f, 1.0f);          // Top Right Of The Quad (Left)
		glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Left)
		glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Left)
		glVertex3f(-1.0f,-1.0f, 1.0f);          // Bottom Right Of The Quad (Left)
		glColor3f(1.0f,0.0f,1.0f);          // Set The Color To Violet
		glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Right)
		glVertex3f( 1.0f, 1.0f, 1.0f);          // Top Left Of The Quad (Right)
		glVertex3f( 1.0f,-1.0f, 1.0f);          // Bottom Left Of The Quad (Right)
		glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Right)
    glEnd();                            			// Done Drawing The Quad

	// swap buffers to display, since we're double buffered.
	glutSwapBuffers();

	rtri += 3.0;
	rquad -= 5.0;
}

/* The function called whenever a key is pressed. */
void keyPressed(unsigned char key, int x, int y)
{
	/* avoid thrashing this procedure */
	usleep(100);

	/* If escape is pressed, kill everything. */
	if (key == ESCAPE)
	{
		/* shut down our window */
		glutDestroyWindow(window);

		/* exit the program...normal termination. */
		exit(0);
	}

	if (key == 98)
	{
		glutDestroyWindow(window); 		// Kill Our Current Window
		fullscreen = !fullscreen;		// Toggle Fullscreen / Windowed Mode
		// Recreate Our OpenGL Window ( Modified )
		window = glutCreateWindow("NeHe's Rotation Tutorial");
		glutDisplayFunc(&DrawGLScene);

		if (fullscreen)
			glutFullScreen();
		glutIdleFunc(&DrawGLScene);

		InitGL(640,480);
	}
}

int main(int argc, char **argv)
{
	/* Initialize GLUT state - glut will take any command line arguments that pertain to it or
     X Windows - look at its documentation at http://reality.sgi.com/mjk/spec3/spec3.html */
	glutInit(&argc, argv);

	/* Select type of Display mode:
     Double buffer
     RGBA color
     Alpha components supported
     Depth buffer */
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);

	/* get a 640 x 480 window */
	glutInitWindowSize(640, 480);

	/* the window starts at the upper left corner of the screen */
	glutInitWindowPosition(0, 0);

	/* Open a window */
	window = glutCreateWindow("Jeff Molofee's GL Code Tutorial ... NeHe '99");

	/* Register the function to do all our OpenGL drawing. */
	glutDisplayFunc(&DrawGLScene);

	/* Go fullscreen.  This is as soon as possible. */
	glutFullScreen();
	fullscreen = true;

	/* Even if there are no events, redraw our gl scene. */
	glutIdleFunc(&DrawGLScene);

	/* Register the function called when our window is resized. */
	glutReshapeFunc(&ReSizeGLScene);

	/* Register the function called when the keyboard is pressed. */
	glutKeyboardFunc(&keyPressed);

	/* Initialize our window. */
	InitGL(640, 480);

	/* Start Event Processing Engine */
	glutMainLoop();

	return 1;
}

